﻿using Microsoft.Extensions.Configuration;
using NLog;
using Stee.CAP8.MessageBus.Interface.Interfaces;
using Stee.CAP8.MessageBus.Interface.Models;
using Stee.CAP8.MessageBus.Sagas.Core.Common;
using Stee.CAP8.MessageBus.Sagas.Payment.Dtos;
using System;
using Microsoft.Extensions.DependencyInjection;
using System.Threading;

namespace Stee.CAP8.MessageBus.Sagas.Payment.Sagas
{
    public class SubSagaHandler
    {

        private ISubscriber _objectSubscriber;
        private IPublisher _objectPublisher;
        private readonly IServiceProvider _provider;
        private static readonly Logger Logger = LogManager.GetCurrentClassLogger();

        public const string ConfigurationFileJSON = "appsettings.json";

        private readonly string topic = "";
        private static readonly string key = "first_key";

        private readonly IConfigurationRoot ConfigurationRoot;
        private readonly TopicName topicNameObject = null;
        public SubSagaHandler(ISubscriber objectSubscriber, IPublisher objectPublisher, IServiceProvider provider)
        {
            _objectSubscriber = objectSubscriber ?? throw new ArgumentNullException(nameof(objectSubscriber));
            _objectPublisher = objectPublisher ?? throw new ArgumentNullException(nameof(objectPublisher));
            _provider = provider ?? throw new ArgumentNullException(nameof(provider));
            ConfigurationRoot = new ConfigurationBuilder().AddJsonFile(ConfigurationFileJSON, false)
               .Build();

            topic = ConfigurationRoot.GetSection("MessageBusPublish").GetSection("TopicID").Value;
            topicNameObject = new TopicName(topic, key);
        }

        public void HandleEvent()
        {
            //topic read co
            _objectSubscriber.Initialize(topicNameObject, OnCommandReceived, OnSubscriberError);

            if (_objectSubscriber.IsInitialized)
            {
                _objectSubscriber.Subscribe();
            }
        }

        /// <summary>
        /// Mock example method name format, "On<Action><Response>".
        /// Error handler for subscriber.
        /// </summary>
        /// <param name="errorCode">Broker error code</param>
        /// <param name="isFatal">Flag indicating fatal error</param>
        private static void OnSubscriberError(string errorCode, bool isFatal)
        {
            if (string.IsNullOrEmpty(errorCode))
            {
                Logger.Warn($"Unexpected subscriber error, no error code returned. Is fatal: {isFatal}");
            }
            else
            {
                Logger.Error($"Subscriber error: {errorCode}, Is fatal: {isFatal}");
            }
        }


        /// <summary>
        /// Handle message of CommandMessage type
        /// </summary>
        /// <param name="topicName">Topic name</param>
        /// <param name="message">Command message</param>
        /// <returns>Return TRUE if consumed successfully else FALSE</returns>
        private bool OnCommandReceived(TopicName topicName, CommandMessage message)
        {

            try
            {
                if (topicName == null)
                {
                    throw new ArgumentNullException(nameof(topicName));
                }
                else if (message == null)
                {
                    throw new ArgumentNullException(nameof(message));
                }
                

                var action = message.Action;
                var source = message.Source;
                //根据action信息适配sagaHandler
                if (action == "PaymentSub.Payment")
                {
                    var data = message.Data.ToObject<PaymentInfo>();
                    if (data == null)
                    {
                        throw new Exception("传入错误的数据类型");
                    }
                    var service = _provider.GetService<PaymentSub>();
                    service.Payment(data).Wait();
                    message.Data = data.ObjToBytes();
                   


                }
                else
                {

                }


                ReplyCommand(message);



                return true;
            }
            catch (Exception ex)
            {
                Logger.Error(ex, ex.Message);
                return false;

            }
        }

        private void ReplyCommand(CommandMessage message)
        {
            this._objectPublisher.Initialize(this.OnPersonPublished, OnPublisherError);
            //replay信息
            TopicName topicInfo = new TopicName(message.ReplyChannel, message.ReplyChannel);
            if (_objectPublisher.IsInitialized)
            {
                var objectPublishToken = new CancellationTokenSource();
                if (this._objectPublisher.PublishCommand(topicInfo, message, objectPublishToken.Token))
                {
                    string msg = $"Publish CommandMessage object => {message}";
                    Console.WriteLine(msg);
                }
                else
                {
                    string msg = $"[Error] Publish CommandMessage object failed => {message}";
                    Console.WriteLine(msg);
                }
            }
        }

        /// <summary>
        /// Mock example method name format, "On<Type><Action>".
        /// Publish response handler for Person data type messages.
        /// </summary>
        /// <param name="publishOutcome">Message publish outcome</param>
        /// <returns>Return TRUE if handled successfully else FALSE</returns>
        private bool OnPersonPublished(PublishOutcome publishOutcome)
        {
            bool isHandled = false;

            if (publishOutcome != null)
            {
                //// Handle your process outcome here
                isHandled = true;
            }

            return isHandled;
        }


        /// <summary>
        /// Mock example method name format, "On<Action><Response>".
        /// Publish error handler for broker publish error.
        /// </summary>
        /// <param name="errorCode">Publish error code</param>
        /// <param name="isFatal">Flag indicating fatal error</param>
        private void OnPublisherError(string errorCode, bool isFatal)
        {
            if (string.IsNullOrEmpty(errorCode))
            {
                Logger.Warn($"Unexpected publisher error, no error code returned. Is fatal: {isFatal}");
            }
            else
            {
                Logger.Error($"Publisher error: {errorCode}, Is fatal: {isFatal}");
            }
        }


    }
}
